/*
 * Copyright 2002-2021 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory;

import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;

/**
 * 用于访问Spring bean容器的根接口.
 *
 * <p>这是bean容器的基本客户端视图; 其他接口, 如{@link ListableBeanFactory}和
 * {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}
 * 可用于特定用途.
 *
 * <p>这个接口是由包含许多bean定义的对象实现的, 每个定义都由String名称唯一标识. 根据bena的定义,
 * 工厂将返回包含对象的独立实例(Prototype设计模式)或单个共享实例(Singleton设计模式的高级替代方案,
 * 其中实例是工厂范围内的单例). 将返回那种类型的实例取决于bean工厂配置: API是相同的. 自Spring 2.0
 * 以来, 根据具体的application context(例如,web环境中的"request"和"session"作用于), 可以使用
 * 更多的作用域.
 *
 * <p>这种方法的要点是BeanFactory是应用程序组件的中央注册表, 并集中应用程序组件配置(例如, 单个对象
 * 不再需要读取properties文件). 请参阅""Expert One-on-One J2EE Design and Development"的
 * 第4章和第11章, 以了解此方法的好处.
 *
 * <p>请注意, 通常最好依靠依赖注入("push"配置)通过setter或构造函数来配置应用程序对象, 而不是使用
 * 任何形式的"pull"配置, 如BeanFactory查找. Spring的依赖注入功能是使用这个BeanFactory接口及其
 * 子接口实现的.
 *
 * <p>通常, BeanFactory将加载存储在配置源(如XML文档)中的bean定义, 并使用
 * {@code org.springframework.beans}包来配置bean. 然而, 一个实现可以简单地返回它在
 * 必要时直接在Java代码中创建的Java对象. 定义的存储方式没有任何限制: LDAP、RDBMS、XML、
 * properties文件等. 估计实现支持bean之间的引用(依赖注入).
 *
 * <p>与{@link ListableBeanFactory}中的方法相反, 如果这是{@link HierarchicalBeanFactory},
 * 则该接口中的所有操作也将检查父工厂. 如果在这个功能实例中没有找到bean, 则会询问直接的父工厂.
 * 这个工厂实例中的bean应该覆盖任何工厂中相同名称的bean.
 *
 * <p>Bean factory实现应该尽可能支持标准的bean生命周期接口. 整套初始化方法及其标准顺序为:
 * <ol>
 * <li>BeanNameAware's {@code setBeanName}
 * <li>BeanClassLoaderAware's {@code setBeanClassLoader}
 * <li>BeanFactoryAware's {@code setBeanFactory}
 * <li>EnvironmentAware's {@code setEnvironment}
 * <li>EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
 * <li>ResourceLoaderAware's {@code setResourceLoader}
 * (only applicable when running in an application context)
 * <li>ApplicationEventPublisherAware's {@code setApplicationEventPublisher}
 * (only applicable when running in an application context)
 * <li>MessageSourceAware's {@code setMessageSource}
 * (only applicable when running in an application context)
 * <li>ApplicationContextAware's {@code setApplicationContext}
 * (only applicable when running in an application context)
 * <li>ServletContextAware's {@code setServletContext}
 * (only applicable when running in a web application context)
 * <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors
 * <li>InitializingBean's {@code afterPropertiesSet}
 * <li>a custom {@code init-method} definition
 * <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
 * </ol>
 *
 * <p>在bean factory关闭时, 应用以下生命周期方法:
 * <ol>
 * <li>{@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
 * <li>DisposableBean's {@code destroy}
 * <li>a custom {@code destroy-method} definition
 * </ol>
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Chris Beams
 * @since 13 April 2001
 * @see BeanNameAware#setBeanName
 * @see BeanClassLoaderAware#setBeanClassLoader
 * @see BeanFactoryAware#setBeanFactory
 * @see org.springframework.context.EnvironmentAware#setEnvironment
 * @see org.springframework.context.EmbeddedValueResolverAware#setEmbeddedValueResolver
 * @see org.springframework.context.ResourceLoaderAware#setResourceLoader
 * @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher
 * @see org.springframework.context.MessageSourceAware#setMessageSource
 * @see org.springframework.context.ApplicationContextAware#setApplicationContext
 * @see org.springframework.web.context.ServletContextAware#setServletContext
 * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization
 * @see InitializingBean#afterPropertiesSet
 * @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName
 * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization
 * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
 * @see DisposableBean#destroy
 * @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName
 */
public interface BeanFactory {

	/**
	 * 用于解引用{@link FactoryBean}实例, 并将其与FactoryBean<i>创建的</i>bean区分开来.
	 * 例如, 如果名为{@code myJndiObject}的bean是一个FactoryBean, 那么获取{@code &myJndiObject}
	 * 将返回工厂, 而不是工厂返回的实例.
	 */
	String FACTORY_BEAN_PREFIX = "&";


	/**
	 * 返回指定bean的一个实例, 该实例可以是共享的, 也可以是独立的.
	 * <p>这种方法允许使用Spring BeanFactory来替代Single通或Prototype设计模式.
	 * 在Singleton bean的情况下, 调用者可以保留对返回对象的引用.
	 * <p>将别名翻译回相应的规范bean名称.
	 * <p>将询问父工厂是否在此工厂实例中找不到bean.
	 * @param name 要检索的bean的名称
	 * @return 一个bean的实例
	 * @throws NoSuchBeanDefinitionException if there is no bean with the specified name
	 * @throws BeansException if the bean could not be obtained
	 */
	Object getBean(String name) throws BeansException;

	/**
	 * 返回指定bean的一个实例, 该实例可以是共享的, 也可以是独立的.
	 * <p>行为与{@link #getBean(String)}相同, 但如果bean不是所需类型, 则通过抛出
	 * BeanNotOfRequiredTypeException来提供类型安全措施. 这意味着ClassCastException
	 * 不能像{@link #getBean(String)}那样在正确地转换结果时抛出.
	 * <p>将别名翻译回相应的规范bean名称.
	 * <p>将询问父工厂是否在此工厂实例中找不到bean.
	 * @param name 要检索的bean的名称
	 * @param requiredType bean必须匹配的类型; 可以是接口或超类
	 * @return 一个bean的实例
	 * @throws NoSuchBeanDefinitionException 如果没有这样的bean定义
	 * @throws BeanNotOfRequiredTypeException 如果bean不是所需的类型
	 * @throws BeansException 如果无法创建bean
	 */
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;

	/**
	 * 返回指定bean的一个实例, 该实例可以是共享的, 也可以是独立的.
	 * <p>允许指定显式构造函数参数/工厂方法参数, 覆盖bean定义中指定的默认参数(如果有的话).
	 * @param name 要检索的bean的名称
	 * @param args 使用显式参数创建bean实例时使用的参数(仅在创建新实例而不是检索现有实例时应用)
	 * @return 一个bean的实例
	 * @throws NoSuchBeanDefinitionException 如果没有这样的bean定义
	 * @throws BeanDefinitionStoreException 如果已经给出了参数, 但受影响的bean不是prototype
	 * @throws BeansException 如果无法创建bean
	 * @since 2.5
	 */
	Object getBean(String name, Object... args) throws BeansException;

	/**
	 * 返回唯一匹配给定对象类型的bean实例(如果有的话).
	 * <p>该方法进入按类型查找的{@link ListableBeanFactory}区域, 但也可以转换为基于给定类型的名称的
	 * 传统按名称查找. 对于跨bean集的更广泛的检索操作, 请使用{@link ListableBeanFactory} and/or
	 * {@link BeanFactoryUtils}.
	 * @param requiredType bean必须匹配的类型; 可以是接口或超类
	 * @return 与所需类型匹配的单个bean的实例
	 * @throws NoSuchBeanDefinitionException 如果没有找到给定类型的bean
	 * @throws NoUniqueBeanDefinitionException 如果找到多个给定类型的bean
	 * @throws BeansException 如果无法创建bean
	 * @since 3.0
	 * @see ListableBeanFactory
	 */
	<T> T getBean(Class<T> requiredType) throws BeansException;

	/**
	 * 返回指定bean的一个实例, 该实例可以是共享的, 也可以是独立的.
	 * <p>允许指定显式构造函数参数/工厂方法参数, 覆盖bean定义中指定的默认参数(如果有).
	 * <p>此方法进入按类型查找的{@link ListableBeanFactory}区域, 但也可以转换为基于给定类型的名称的
	 * 传统按名称查找. 对于跨bean集的更广泛的检索操作, 请使用{@link ListableBeanFactory} and/or
	 * {@link BeanFactoryUtils}.
	 * @param requiredType bean必须匹配的类型; 可以是接口或超类
	 * @param args 使用显示参数创建bean实例时要使用的参数(仅在创建新实例而不是检索现有实例时应用)
	 * @return 一个bean的实例
	 * @throws NoSuchBeanDefinitionException 如果没有这样的bean定义
	 * @throws BeanDefinitionStoreException 如果已经给出了参数, 但受影响的bean不是prototype
	 * @throws BeansException 如果无法创建bean
	 * @since 4.1
	 */
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

	/**
	 * 返回指定bean的provider, 允许延迟按需检索实例, 包括可用心和唯一性选项.
	 * @param requiredType bean必须匹配的类型; 可以是接口或超类
	 * @return 对应的provider handle
	 * @since 5.1
	 * @see #getBeanProvider(ResolvableType)
	 */
	<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

	/**
	 * 返回指定bean的provider, 允许延迟按需检索实例, 包括可用心和唯一性选项.
	 * @param requiredType bean必须匹配的类型; 可以是泛型类型声明.
	 * 请注意, 与反射注入点不同, 此处不支持collection类型. 要以编程方式检索与特定类型匹配的bean列表,
	 * 请在此处指定实际的bean类型作为参数, 然后使用{@link ObjectProvider#orderedStream()}或其
	 * lazy streaming/iteration选项.
	 * @return 对应的provider的handle
	 * @since 5.1
	 * @see ObjectProvider#iterator()
	 * @see ObjectProvider#stream()
	 * @see ObjectProvider#orderedStream()
	 */
	<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

	/**
	 * 这个bean工厂是否包含给定名称的bean定义或外部注册的Singleton实例?
	 * <p>如果给定的名时一个别名, 它将被翻译回相应的规范bean名称.
	 * <p>如果这个工厂是分层的, 将询问任何父工厂是否在这个工厂实例中找不到bean.
	 * <p>如果找到与给定名称匹配的bean定义或singleton实例, 则无论命名的bean定义是具体的还是abstract、
	 * lazy或eager、在scope内还是非scope内的, 该方法都将返回{@code true}. 因此请注意, 此方法的
	 * {@code true}返回值并不一定表示{@link #getBean}能够获得相同名称的实例.
	 * @param name 要查询的bean的名称
	 * @return 是否存在具有给定名称的bean
	 */
	boolean containsBean(String name);

	/**
	 * 这个bean是共享的还是Singleton? 也就是说, {@link #getBean}会一直返回相同的实例吗?
	 * <p>注意: 这种返回{@code false}的方法并不能清楚地指示独立的实例. 它指示非Singlton实例, 这些实例
	 * 也可能对应于作用于bean. 使用{@link #isPrototype}操作可以显示检查独立实例.
	 * <p>将别名翻译回相应的规范bean名称.
	 * <p>将询问父工厂是否在此工厂实例中找不到bean.
	 * @param name 要查询的bean的名称
	 * @return 这个bean是否对应于一个singleton实例
	 * @throws NoSuchBeanDefinitionException 如果没有具有给定名称的bean
	 * @see #getBean
	 * @see #isPrototype
	 */
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	/**
	 * 这个bean是prototype? 也就是说, {@link #getBean}总是会返回独立的实例?
	 * <p>注意: 这个方法返回{@code false}并没有明确地指示一个singleton对象. 它指示非独立实例,
	 * 这些实例也可能对应于作用域bean. 使用{@link #isSingleton}操作来显式检查共享的singleton实例.
	 * <p>将别名翻译回相应的规范bean名称.
	 * <p>将询问父工厂是否在此工厂实例中找不到bean.
	 * @param name 要查询的bean的名称
	 * @return 这个bean是否总是提供独立的实例
	 * @throws NoSuchBeanDefinitionException 如果没有具有给定名称的bean
	 * @since 2.0.3
	 * @see #getBean
	 * @see #isSingleton
	 */
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	/**
	 * 检查具有给定名称的bean是否与指定的类型匹配.
	 * 更具体地说, 检查给定名称的{@link #getBean}调用是否会返回可分配给指定目标类型的对象.
	 * <p>将别名翻译回相应的规范bean名称.
	 * <p>将询问父工厂是否在此工厂实例中找不到bean.
	 * @param name 要查询的bean的名称
	 * @param typeToMatch 要匹配的类型(作为{@code ResolvableType})
	 * @return 如果bean类型匹配, 则为{@code true}; 如果不匹配或尚未确定, 则为{@code false}
	 * @throws NoSuchBeanDefinitionException 如果没有具有给定名称的bean
	 * @since 4.2
	 * @see #getBean
	 * @see #getType
	 */
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	/**
	 * 检查具有给定名称的bean是否与指定的类型匹配.
	 * 更具体地说, 检查给定名称的{@link #getBean}调用是否会返回可分配给指定目标类型的对象.
	 * <p>将别名翻译回相应的规范bean名称.
	 * <p>将询问父工厂是否在此工厂实例中找不到bean.
	 * @param name 要查询的bean的名称
	 * @param typeToMatch 要匹配的类型(作为{@code Class})
	 * @return 如果bean类型匹配, 则为{@code true}; 如果不匹配或尚未确定, 则为{@code false}
	 * @throws NoSuchBeanDefinitionException 如果没有具有给定名称的bean
	 * @since 2.0.1
	 * @see #getBean
	 * @see #getType
	 */
	boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	/**
	 * 确定具有给定名称的bean的类型. 更具体地说, 确定{@link #getBean}将为给定名称返回对象类型.
	 * <p>对于{@link FactoryBean}, 返回FactoryBean创建的对象类型, 由{@link FactoryBean#getObjectType()}
	 * 公开. 这可能会导致初始化以前未初始化的{@code FactoryBean} (参见{@link #getType(String, boolean)}).
	 * <p>将别名翻译回相应的规范bean名称.
	 * <p>将询问父工厂是否在此工厂实例中找不到bean.
	 * @param name 要查询的bean的名称
	 * @return bean的类型, 如果不可确定, 则为{@code null}
	 * @throws NoSuchBeanDefinitionException 如果没有具有给定名称的bean
	 * @since 1.1.2
	 * @see #getBean
	 * @see #isTypeMatch
	 */
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	/**
	 * 确定具有给定名称的bean的类型. 更具体地说, 确定{@link #getBean}将为给定名称返回对象类型.
	 * <p>对于{@link FactoryBean}, 返回FactoryBean创建的对象类型, 由{@link FactoryBean#getObjectType()}
	 * 公开. 根据{@code allowFactoryBeanInit}标志, 如果没有可用的早期类型信息, 这可能会导致先前为初始化的
	 * {@code FactoryBean}初始化.
	 * <p>将别名翻译回相应的规范bean名称.
	 * <p>将询问父工厂是否在此工厂实例中找不到bean.
	 * @param name 要查询的bean的名称
	 * @param allowFactoryBeanInit {@code FactoryBean}是否可以仅仅为了确定其对象类型而被初始化.
	 * @return bean的类型, 如果不可确定, 则为{@code null}
	 * @throws NoSuchBeanDefinitionException 如果没有具有给定名称的bean
	 * @since 5.2
	 * @see #getBean
	 * @see #isTypeMatch
	 */
	@Nullable
	Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;

	/**
	 * 返回给定bean名称的别名(如果有的话).
	 * <p>当在{@link #getBean}调用中使用时, 所有这些别名都指向同一个bean.
	 * <p>如果给定的名称是一个别名, 那么将返回相应的原始bean名称和其他别名(如果有的话),
	 * 原始bean名称是数组中的第一个元素.
	 * <p>将询问父工厂是否在此工厂实例中找不到bean.
	 * @param name 要检查别名的bean名称
	 * @return 别名, 如果没有, 则为空数组
	 * @see #getBean
	 */
	String[] getAliases(String name);

}
